package com.example.receiver;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Date;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.example.constant.ClientConstants;
import com.example.manager.ManagerClient;
import com.example.terminal.bean.VMESS;
import com.example.type.StreamType;
import com.example.util.DataBuilder;
import com.example.util.Des;
import com.google.gson.Gson;

public class UDPReceiver {
	private final static Logger log = LoggerFactory.getLogger(UDPReceiver.class);
	private final static Logger plog = LoggerFactory.getLogger("PackageThread");
	
	/*** com.google.myjson.Gson.Gson */
	private Gson son = new Gson();
	/*** 加解密的key */
	private String key = ClientConstants.key;
	/*** 视频udp */
	private DatagramSocket v_sendsocket;
	/*** 视频视频udp */
	private DatagramSocket r_sendsocket;
	/*** 中转服务器ip */
	private String serverAddressstr;
	/*** 视频线程循环标志位 */
	private boolean v_isThreadRun = true;
	/*** 音频线程循环标志位 */
	private boolean r_isThreadRun = true;
	/*** 解码器 */
//	private Decode decoder;
	/*** 可实现多通道解码 */
	private int decoderindex;
	/*** 一个二维数组 做循环，存放数据 避免数据丢失 */
	private byte[] m_recvpackbuffer;
	private byte[] m_recvframebuffer;
	private int m_checksum = 0; // 用来检查当前帧的包是否完整 1+2+。。。+n
	private int m_currentchecksum = 0; // 用来检查当前帧的包是否完整 1+2+。。。+n
	private byte[] m_recrpackbuffer = new byte[200]; // 音频
	// 帧信息
	public long m_iFrameSerial = -1;
	public int m_iPacketSerial = 0;
	public int m_iPacketNum = 0;
	private int packHeaderSize = 29;
	private int packBodySize = 519;
	// 音频
	private static final int frequency = 44100 / 4;
	private static final int channelConfiguration = 4;
	private static final int audioEncoding = 2;
	private int plyBufSize;
//	private AudioTrack audioTrack;
	private VoiceDecode voicedecoder;
	private long currenttime = 0;
	private DatagramPacket pack1 = null;
//	private Handler handler;
//	private FragmentMonitoring fragment;
	private int vport;
	
//	private StreamType streamType;
	private int heartBeatCount = 0;
	
	private long streamSize;
	
	private static int no;
	
	public UDPReceiver(String ip, int vport, int rport, DatagramSocket v_sendsocket, DatagramSocket r_sendsocket, int heartBeatCount) {
		m_recvframebuffer = new byte[5000000];
		this.v_isThreadRun = true;
		this.r_isThreadRun = true;
//		this.decoderindex = index;
		this.serverAddressstr = ip;
//		this.handler = hand;
//		this.fragment = fragment;
		this.vport = vport;
		this.heartBeatCount = heartBeatCount;
		
		//初始化心跳包，通过视频端口发送，以说明m端还在线
		setPack(vport);
		
		// 播放初始化
//		plyBufSize = AudioTrack.getMinBufferSize(frequency,
//				channelConfiguration, audioEncoding);
//		audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, frequency,
//				channelConfiguration, audioEncoding, plyBufSize * 2,
//				AudioTrack.MODE_STREAM);
//		audioTrack.play();

//		voicedecoder = new VoiceDecode();
//		voicedecoder.initDecode();

//		if(decoder==null){
//			decoder = new Decode();
//			decoder.InitCodec(surface);
//		}

		this.v_sendsocket = v_sendsocket;
		this.r_sendsocket = r_sendsocket;
		
		
		new XTThread().start(); // 开启心跳线程
//		new Thread(v_Runnable).start(); // 开启视频线程
//		new Thread(r_Runnable).start(); // 开启音频线程
		
		synchronized(this){
			no++;
		}
	}
	
	public void setPack(int vport){
		try {
			VMESS vmess = new VMESS();
			vmess.actiontype = "2";
			String xtjson = Des.encryptDES(DataBuilder.buildJson(vmess), key, key);
			pack1 = new DatagramPacket(xtjson.getBytes(), xtjson.getBytes().length, InetAddress.getByName(serverAddressstr), vport);
		} catch (Exception e) {
			log.error("failed to set pack " + e.getMessage());
		}
	}
	
	public String accept(final StreamType streamType) throws Exception {
		return accept(streamType, null);
	}
	
	public String accept(final StreamType streamType, final ManagerClient client) throws Exception {
		final String file = System.getProperty("user.home") + "/test/" + DateFormatUtils.format(new Date(), "yyyyMMdd-HHmmss");
		final Writer writer = new FileWriter(file);
		log.info("writing file {} ", file);
		
		new Thread(new Runnable(){
			public void run() {

				while(true){
					try{
						m_recvpackbuffer = new byte[548];
						DatagramPacket pack = new DatagramPacket(m_recvpackbuffer, m_recvpackbuffer.length, InetAddress.getByName(serverAddressstr), vport);
						
						if(streamType == StreamType.Audio){
							r_sendsocket.receive(pack);
							if(r_sendsocket.isClosed()){
								break;
							}
						}else if(streamType == StreamType.Vedio){
							v_sendsocket.receive(pack);
							if(v_sendsocket.isClosed()){
								break;
							}
						}

						if(client != null){
							client.receivedPakcages++;
						}
						
						int count = 0;
						for(byte b : m_recvpackbuffer){
							if(b != 0){
								count++;
							}else{
								break;
							}
						}
						
						byte[] buffer = new byte[count];
						for(int i = 0; i < count; i++){
							buffer[i] = m_recvpackbuffer[i];
						}
						
						log.debug("write {} bytes to {}", buffer.length, file);
						IOUtils.write(buffer, writer);
						writer.flush();
						
						
					}catch(Exception e){
						log.error("UDPReceiter[" + no + "] accept file type " + streamType + " error " + e.toString());
						try {
							writer.close();
						} catch (IOException e1) {
							log.error("failed to close writer");
							break;
						}
						
						break;
					}
				}
				
				if(client != null){
					client.stopAccept = true;
				}
				
				streamSize = FileUtils.sizeOf(new File(file)); 
			}
		}).start();
		
		return file;
	}

	public void acceptVedio(final int mid, final int no) throws Exception {
		new Thread(new Runnable(){
			public void run() {

				int count = 0;
				
				while(true){
					try{
						m_recvpackbuffer = new byte[274];
						DatagramPacket pack = new DatagramPacket(m_recvpackbuffer, m_recvpackbuffer.length, InetAddress.getByName(serverAddressstr), vport);
						
						v_sendsocket.receive(pack);
						count++;
						System.out.println("manager[" + no + "] received package count " + count);
						plog.info("manager[{}] received package count {}", no, count);
						
					}catch(Exception e){
						log.error("manager[" + no + "] accept file type video error ", e);
						break;
					}
				}
			}
		}).start();
	}
	
	// 通过视频socket发送心跳给N
	class XTThread extends Thread {
		@Override
		public void run() {
			int count = 0;
			
			while (v_isThreadRun) {
				if(heartBeatCount != 0 && count >= heartBeatCount){
					break;
				}else{
					count++;
				}
				
				try {
					if (pack1 != null) {
						v_sendsocket.send(pack1);
						log.debug("持续发送心跳给N");
					}else{
						log.debug("持续发送心跳给N,包为空");
					}
					sleep(500);
				} catch (Exception e) {
					log.debug("M持续发送心跳给N异常" + e.toString());
				}
			}
		}
	}

	public long getStreamSize() {
		return streamSize;
	}
}
